#!/usr/bin/perl -w

# Copyright (c) 2008 Jing Mi <jingmi@baidu.com>.
# All rights reserved.
# DISTRIBUTE UNDER BSDL.

use strict;
use Data::Dumper;
use Time::Local;
use Term::ANSIColor;
use Time::localtime;
use File::stat;

our $version = 0.3;

if (scalar(@ARGV) != 1)
{
    print STDERR "filemonitor Version $version\nError: no input file\n";
    exit(1);
}

my $logfile = shift;
my $filestat = stat($logfile);
my $logsize = $filestat->size;
my $logtime = $filestat->mtime;
my $colorindex = 0;
my @colorarr = ("red", "green", "yellow", "blue", "magenta", "cyan");
our @search_string = ();
our @hide_string = ();
our @weak_string = ();
our $turnon_display = 1;
our $sleep_interval = 1;

for ( ; ; )
{
    my $newfilestat = stat($logfile);
    my $newlogsize = $newfilestat->size;
    my $newlogtime = $newfilestat->mtime;
    if ($newlogsize > $logsize)
    {
        my $buffer;
        open LOGHANDLER, $logfile;
        seek(LOGHANDLER, $logsize, 0);
        read(LOGHANDLER, $buffer, $newlogsize-$logsize, $logsize);
        my @lines = getlines($buffer);
        if ($colorindex >= scalar(@colorarr))
        {
            $colorindex = 0;
        }
        displaylines(\@lines, $colorarr[$colorindex++]);
        my $nowtime = "[ " . localtime->hour() . ":" . localtime->min() . ":".  localtime->sec() . " ]";
        my $linecounter = sprintf("(%3d)", scalar(@lines));
        print "-------------------------------------------------- ", $nowtime, $linecounter, "\n" if ($turnon_display == 1);
        close LOGHANDLER;
    }
    $logsize = $newlogsize;
    $logtime = $newlogtime;
    my ($read_io, $io_out) = ('', '');
    vec($read_io, fileno(STDIN), 1) = 1;
    my $nfound = select($io_out=$read_io, undef, undef, $sleep_interval);
    if ($nfound == 1)
    {
        my $input = <STDIN>;
        chomp($input);
        if ($input eq '')
        {
            next;
        }
        elsif ($input eq "cls")
        {
            for (my $i=0; $i<100; $i++)
            {
                print "\n";
            }
            print "[" . $input . "]\n";
        }
        elsif ($input =~ /^find/)
        {
            $input =~ s/^find (.*)/$1/sm;
            print color("red on_white") . "find: " . $input . color("reset") . color("white on_black") . "\n";
            push(@search_string, $input);
        }
        elsif ($input =~ /^unfind/)
        {
            $input =~ s/^unfind (.*)/$1/sm;
            for (my $i=0; $i<scalar(@search_string); $i++)
            {
                if ($input eq $search_string[$i])
                {
                    if ($i == scalar(@search_string)-1)
                    {
                        pop @search_string;
                    }
                    else
                    {
                        $search_string[$i] = pop @search_string;
                    }
                }
            }
        }
        elsif ($input eq 'display')
        {
            print color("red");
            print Dumper(@search_string);
            print color("green");
            print Dumper(@hide_string);
            print color("white");
            print Dumper(@weak_string);
            print color("yellow");
            print "sleep interval: ", $sleep_interval, "\n";
            print "display turned off\n" if ($turnon_display == 0);
            print "display turned on\n" if ($turnon_display == 1);
            print color("reset");
        }
        elsif ($input =~ /^hide/)
        {
            $input =~ s/^hide (.*)/$1/sm;
            print color("green on_white") . "hide: " . $input . color("reset") . color("white on_black") . "\n";
            push(@hide_string, $input);
        }
        elsif ($input =~ /^unhide/)
        {
            $input =~ s/unhide (.*)/$1/sm;
            for (my $i=0; $i<scalar(@hide_string); $i++)
            {
                if ($input eq $hide_string[$i])
                {
                    if ($i == scalar(@hide_string)-1)
                    {
                        pop @hide_string;
                    }
                    else
                    {
                        $hide_string[$i] = pop @hide_string;
                    }
                }
            }
        }
        elsif ($input =~ /^weak/)
        {
            $input =~ s/^weak (.*)/$1/sm;
            print color("white") . "weak: " . $input . color("reset") . "\n";
            push(@weak_string, $input);
        }
        elsif ($input =~ /^unweak/)
        {
            $input =~ s/unweak (.*)/$1/sm;
            for (my $i=0; $i<scalar(@weak_string); $i++)
            {
                if ($input eq $weak_string[$i])
                {
                    if ($i == scalar(@weak_string)-1)
                    {
                        pop @weak_string;
                    }
                    else
                    {
                        $weak_string[$i] = pop @weak_string;
                    }
                }
            }
        }
        elsif ($input eq 'turnoff')
        {
            $turnon_display = 0;
        }
        elsif ($input eq 'turnon')
        {
            $turnon_display = 1;
        }
        elsif ($input =~ /^sleep/)
        {
            $input =~ s/^sleep (\d+)/$1/sm;
            $sleep_interval = $input;
        }
        elsif ($input eq 'help')
        {
            print color('green');
            print "SIMPLE USAGE $version\n";
            print "find / unfind STRING\n";
            print "hide / unhide STRING\n";
            print "weak / unweak STRING\n";
            print "display: display runtime variables\n";
            print "sleep SECONDS: monitor file every SECONDS\n";
            print "turnon / turnoff: turn on/off display\n";
            print "help: show this screen\n";
            print "\t\t", '-- Powered by jingmi@baidu.com', "\n";
            print color('reset');
        }
    }
}

sub getlines
{
    my $buffer = shift;
    my @lines = split(/\n/, $buffer);

    return @lines;
}

sub displaylines
{
    my $lines_ref = shift;
    my $color = shift;
    return if ($turnon_display == 0);
    NEXTLINE:
    foreach my $line (@$lines_ref)
    {
        foreach my $pattern (@hide_string)
        {
            if ($line =~ /$pattern/)
            {
                next NEXTLINE;
            }
        }
        foreach my $weakpattern (@weak_string)
        {
            if ($line =~ /$weakpattern/)
            {
                $line = color("white") . $line. color("reset") . color($color);
            }
        }
        foreach my $pattern (@search_string)
        {
            if ($line =~ /$pattern/)
            {
                my $newpattern = color("red on_blue") . $pattern . color("reset on_black") . color($color);
                $line =~ s/$pattern/$newpattern/gsm;
            }
        }
        print color($color) . $line . color("reset") . "\n";
    }
}
